﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MacomberMapSystem.Common.Database;
using System.Drawing;

namespace MacomberMapSystem.Common.Internals
{/// <summary>
    /// This class provides a tally dictionary of counts per user
    /// </summary>
    public class TallyDictionary
    {
        #region Enumerations
        /// <summary>
        /// Our collection of one-line classifications
        /// </summary>
        public enum enumOneLineCategory
        {
            Assigned_OneLines_Today,
            Assigned_Fixes_Today,
            Assigned_OneLines_Total,
            Assigned_Fixes_Total,

            Repaired_OneLines_Today,
            Repaired_Errors_Today,
            Repaired_Warnings_Today,
            Repaired_Fixes_Today,
            Repaired_OneLines_Total,
            Repaired_Errors_Total,
            Repaired_Warnings_Total,
            Repaired_Fixes_Total,


            Total_Errors,
            Total_Warnings,

        }

        /// <summary>
        /// Our collection of one-line summary data
        /// </summary>
        public enum enumOneLineSummary
        {
            New_One_Lines,
            One_Lines_Completed_InFuture_Count
        }
        #endregion

        #region Variable declarations
        /// <summary>Our collection of latest models</summary>
        public Dictionary<String, MM_Database_Model> LatestModels = new Dictionary<string, MM_Database_Model>();

        /// <summary>Our dictionary of fixes for each user</summary>
        public SortedDictionary<MM_Database_User, Dictionary<enumOneLineCategory, int>> FixesByUser = new SortedDictionary<MM_Database_User, Dictionary<enumOneLineCategory, int>>();

        /// <summary>Our dictionary of fixes for each user, by date</summary>
        public SortedDictionary<MM_Database_User, SortedDictionary<DateTime, Dictionary<enumOneLineCategory, int>>> FixesByDate = new SortedDictionary<MM_Database_User, SortedDictionary<DateTime, Dictionary<enumOneLineCategory, int>>>();

        /// <summary>Our dictionary of fixes for each user, by month</summary>
        public SortedDictionary<DateTime, SortedDictionary<MM_Database_User, int[]>> FixesByMonth = new SortedDictionary<DateTime, SortedDictionary<MM_Database_User, int[]>>();

        /// <summary>Our collection of fixes by model</summary>
        public SortedDictionary<MM_Database_Model, Dictionary<enumOneLineCategory, int>> FixesByModel = new SortedDictionary<MM_Database_Model, Dictionary<enumOneLineCategory, int>>();

        /// <summary>Our total user</summary>
        public MM_Database_User Total;

        /// <summary>Our collection of monthly statistics</summary>
        public SortedDictionary<DateTime, Dictionary<enumOneLineSummary, int>> MonthlySummary = new SortedDictionary<DateTime, Dictionary<enumOneLineSummary, int>>();
        #endregion


        #region Initialization
        /// <summary>
        /// Initialize a new tally dictionary
        /// </summary>
        public TallyDictionary()
        {
            FixesByUser = new SortedDictionary<MM_Database_User, Dictionary<enumOneLineCategory, int>>();
            FixesByModel = new SortedDictionary<MM_Database_Model, Dictionary<enumOneLineCategory, int>>();
            FixesByDate = new SortedDictionary<MM_Database_User, SortedDictionary<DateTime, Dictionary<enumOneLineCategory, int>>>();
            Total = new MM_Database_User("Total", "Total", "Total", "Total", MM_Database_User.enumUserState.Available, new Bitmap(64, 64), null);
            AddUser(Total);
        }

        /// <summary>
        /// Add a user to our database
        /// </summary>
        /// <param name="User"></param>
        public void AddUser(MM_Database_User User)
        {

            Dictionary<enumOneLineCategory, int> NewDic = new Dictionary<enumOneLineCategory, int>();
            foreach (enumOneLineCategory Category in Enum.GetValues(typeof(enumOneLineCategory)))
                NewDic.Add(Category, 0);

            FixesByUser.Add(User, NewDic);
            FixesByDate.Add(User, new SortedDictionary<DateTime, Dictionary<enumOneLineCategory, int>>());
        }

        /// <summary>
        /// Add a new substation event
        /// </summary>
        /// <param name="Model"></param>
        /// <param name="AssignmentDate"></param>
        /// <param name="SummaryItem"></param>
        public void AddMonthlySummary(MM_Database_Model Model, DateTime AssignmentDate, enumOneLineSummary SummaryItem)
        {
            DateTime CurMonth = new DateTime(AssignmentDate.Year, AssignmentDate.Month, DateTime.DaysInMonth(AssignmentDate.Year, AssignmentDate.Month));
            Dictionary<enumOneLineSummary, int> FoundSummaries;
            if (!MonthlySummary.TryGetValue(CurMonth, out FoundSummaries))
                MonthlySummary.Add(CurMonth, FoundSummaries = new Dictionary<enumOneLineSummary, int>());
            if (FoundSummaries.ContainsKey(SummaryItem))
                FoundSummaries[SummaryItem]++;
            else
                FoundSummaries.Add(SummaryItem, 1);
        }

        /// <summary>
        /// Add an assignment event to our collection
        /// </summary>
        /// <param name="User"></param>
        /// <param name="Model"></param>
        /// <param name="Errors"></param>
        /// <param name="Warnings"></param>
        /// <param name="AssignedOn"></param>
        public void AddAssignment(MM_Database_User User, MM_Database_Model Model, int Errors, int Warnings, DateTime AssignedOn)
        {
            FixesByUser[User][enumOneLineCategory.Total_Errors] += Errors;
            FixesByUser[User][enumOneLineCategory.Total_Warnings] += Warnings;

            //Check for assignment within 24 hours, and if so, add to our collection
            if ((DateTime.Now - AssignedOn).TotalHours <= 24.0)
            {
                FixesByUser[User][enumOneLineCategory.Assigned_OneLines_Today]++;
                FixesByUser[User][enumOneLineCategory.Assigned_Fixes_Today] += Errors + Warnings;
            }

            //Add to our collection of assignments overall
            FixesByUser[User][enumOneLineCategory.Assigned_OneLines_Total]++;
            FixesByUser[User][enumOneLineCategory.Assigned_Fixes_Total] += Errors + Warnings;

            //Kick off our total event to update
            if (User.Nickname != "Total")
                AddAssignment(Total, Model, Errors, Warnings, AssignedOn);
            else
            {
                Dictionary<enumOneLineCategory, int> FoundModel;
                if (!FixesByModel.TryGetValue(Model, out FoundModel))
                {
                    FixesByModel.Add(Model, FoundModel = new Dictionary<enumOneLineCategory, int>(2));
                    FoundModel.Add(enumOneLineCategory.Total_Errors, Errors);
                    FoundModel.Add(enumOneLineCategory.Total_Warnings, Warnings);
                }
                else
                {
                    FoundModel[enumOneLineCategory.Total_Warnings] += Warnings;
                    FoundModel[enumOneLineCategory.Total_Errors] += Errors;
                }
            }
        }


        /// <summary>
        /// Add a completion event
        /// </summary>
        /// <param name="User"></param>
        /// <param name="Model"></param>
        /// <param name="Errors"></param>
        /// <param name="Warnings"></param>
        /// <param name="CompletedOn"></param>
        public void AddCompletion(MM_Database_User User, MM_Database_Model Model, int Errors, int Warnings, DateTime CompletedOn)
        {
            FixesByUser[User][enumOneLineCategory.Repaired_Errors_Total] += Errors;
            FixesByUser[User][enumOneLineCategory.Repaired_Warnings_Total] += Warnings;
            FixesByUser[User][enumOneLineCategory.Repaired_Fixes_Total] += Errors + Warnings;
            FixesByUser[User][enumOneLineCategory.Repaired_OneLines_Total]++;
            if ((DateTime.Now - CompletedOn).TotalHours <= 24.0)
            {
                FixesByUser[User][enumOneLineCategory.Repaired_OneLines_Today]++;
                FixesByUser[User][enumOneLineCategory.Repaired_Errors_Today] += Errors;
                FixesByUser[User][enumOneLineCategory.Repaired_Warnings_Today] += Warnings;
                FixesByUser[User][enumOneLineCategory.Repaired_Fixes_Today] += Errors + Warnings;
            }

            //Handle our date-based updates
            Dictionary<enumOneLineCategory, int> DateCollection;
            if (!FixesByDate[User].TryGetValue(CompletedOn.Date, out DateCollection))
            {
                FixesByDate[User].Add(CompletedOn.Date, DateCollection = new Dictionary<enumOneLineCategory, int>(Enum.GetValues(typeof(enumOneLineCategory)).Length));
                DateCollection.Add(enumOneLineCategory.Repaired_Errors_Today, Errors);
                DateCollection.Add(enumOneLineCategory.Repaired_Warnings_Today, Warnings);
                DateCollection.Add(enumOneLineCategory.Repaired_Fixes_Today, Errors + Warnings);
                DateCollection.Add(enumOneLineCategory.Repaired_OneLines_Today, 1);
            }
            else
            {
                DateCollection[enumOneLineCategory.Repaired_Errors_Today] += Errors;
                DateCollection[enumOneLineCategory.Repaired_Warnings_Today] += Warnings;
                DateCollection[enumOneLineCategory.Repaired_Fixes_Today] += Errors + Warnings;
                DateCollection[enumOneLineCategory.Repaired_OneLines_Today]++;
            }

            DateTime MonthOnly = new DateTime(CompletedOn.Date.Year, CompletedOn.Date.Month, DateTime.DaysInMonth(CompletedOn.Date.Year, CompletedOn.Date.Month));

            //First, locate/add our month's results
            SortedDictionary<MM_Database_User, int[]> FoundResults;
            if (!FixesByMonth.TryGetValue(MonthOnly, out FoundResults))
                FixesByMonth.Add(MonthOnly, FoundResults = new SortedDictionary<MM_Database_User, int[]>());

            //Now, locate/add our user's per-month results
            int[] FoundInts;
            if (!FoundResults.TryGetValue(User, out FoundInts))
                FoundResults.Add(User, FoundInts = new int[LatestModels.Count * 3]);

            int Mult = Array.IndexOf(LatestModels.Keys.ToArray(), Model.ModelCategory);

            //If we don't have enough space due to new model categories, update everything
            if (FoundInts.Length < (Mult * 3) + 2)
            {
                foreach (KeyValuePair<DateTime, SortedDictionary<MM_Database_User, int[]>> kvp in FixesByMonth)
                    foreach (MM_Database_User CurUser in kvp.Value.Keys.ToArray())
                    {
                        int[] NewInts = new int[LatestModels.Count * 3];
                        kvp.Value[CurUser].CopyTo(NewInts, 0);
                        kvp.Value[CurUser] = NewInts;
                    }
                FoundResults.TryGetValue(User, out FoundInts);
            }
            

            FoundInts[Mult * 3] = Errors + Warnings;
            FoundInts[(Mult * 3) + 1] = Errors;
            FoundInts[(Mult * 3) + 2] = Warnings;


            //Kick off our total event to update
            if (User.Nickname != "Total")
                AddCompletion(Total, Model, Errors, Warnings, CompletedOn);
        }

        #endregion



    }
}